﻿using System;
using System.Collections.Generic;
using System.Windows;
using GameEngine.Model;
using GameEngine.View.Components;
using PureMVC.Interfaces;
using PureMVC.Patterns;

namespace GameEngine.View
{
    public class WorldMediatorConstants<MyIdType>
        where MyIdType : IComparable<MyIdType> {
        public static string GetMediatorNameFromProxy(IWorldDataProxy<MyIdType> proxy)
        {
            return proxy.ProxyName + "_WorldMediator";
        }
    }

    public class WorldMediator<MyIdType, MyBaseUIElementType> : Mediator
        where MyIdType : IComparable<MyIdType>
    {
        //public const string ADDITEMTOMAP_NOTIFICATION = "MapMediator_AddItem";
        //public const string REMOVEITEMFROMMAP_NOTIFICATION = "MapMediator_RemoveItem";
        //public const string MOUSEONITEMS_NOTIFICATION = "MapMediator_RemoveItem";

        public readonly IWorldDataProxy<MyIdType> proxy;
        public readonly MapMediator< MyIdType, MyBaseUIElementType> mapMediator;
        public readonly IThingMediator<MyIdType, MyBaseUIElementType> itemMediator;
        
        public WorldMediator(
            IWorldDataProxy<MyIdType> worldDataProxy,
            MapMediator<MyIdType, MyBaseUIElementType> mapMediator,
            IThingMediator<MyIdType, MyBaseUIElementType> itemMediator,
            IWorldView<MyIdType, MyBaseUIElementType> view)
            : base(WorldMediatorConstants<MyIdType>.GetMediatorNameFromProxy(worldDataProxy), view)
        {
            this.proxy = worldDataProxy;
            this.mapMediator = mapMediator;
            this.itemMediator = itemMediator;
       }

        void itemMediator_OnPositionChange(IThingDataProxy<MyIdType> obj)
        {
            UpdateItem(obj);
        }

        public new IWorldView<MyIdType, MyBaseUIElementType> ViewComponent
        {
            get { return (IWorldView<MyIdType, MyBaseUIElementType>)base.ViewComponent; }
        }

        #region IMediator Members

        /// <summary>
        /// List the <c>INotification</c> names this <c>Mediator</c> is interested in being notified of
        /// </summary>
        /// <returns>The list of <c>INotification</c> names </returns>
        override public IList<string> ListNotificationInterests()
        {
            IList<String> notifications = base.ListNotificationInterests();
            
            notifications.Add(proxy.THINGADDED_NOTIFICATION);
            notifications.Add(proxy.THINGREMOVED_NOTIFICATION);

            notifications.Add(ModelFacade<MyIdType>.Instance.Game.TILESIZEUPDATED_NOTIFICATION);
            notifications.Add(ModelFacade<MyIdType>.Instance.Game.TILEHEIGHTUNITUPDATED_NOTIFICATION);
            notifications.Add(ModelFacade<MyIdType>.Instance.Game.MAXHEIGHTUPDATED_NOTIFICATION);
            notifications.Add(ModelFacade<MyIdType>.Instance.Game.MINHEIGHTUPDATED_NOTIFICATION);

            //notifications.Add(mapMediator.TILEMOUSELEFTBUTTONUP);
            //?notifications.Add(itemMediator.

            return notifications;
        }

        /// <summary>
        /// Handle <c>INotification</c>s
        /// </summary>
        /// <param name="notification">The <c>INotification</c> instance to handle</param>
        /// <remarks>
        ///     <para>
        ///        Typically this will be handled in a switch statement, with one 'case' entry per <c>INotification</c> the <c>Mediator</c> is interested in. 
        ///     </para>
        /// </remarks>
        override public void HandleNotification(INotification notification)
        {
            switch (notification.Name)
            {
                case MapMediatorConstants<MyIdType>.TILEMOUSELEFTBUTTONUP:
                    if (notification.Type.Equals(proxy.WorldName))
                    {
                        Point position = (Point)notification.Body;
                    }
                    break;
                default:
                    if (notification.Name.Equals(proxy.THINGADDED_NOTIFICATION))
                    {
                        IThingDataProxy<MyIdType> itemProxy = notification.Body as IThingDataProxy<MyIdType>;
                        ViewComponent.AddUIElement(
                            itemMediator.GetThingDataProxyView(itemProxy),
                            itemProxy.Position,
                            proxy.Map.GetTileHeight(itemProxy.Position).Value);
                    }
                    else if (notification.Name.Equals(proxy.THINGREMOVED_NOTIFICATION))
                    {
                        IThingDataProxy<MyIdType> itemProxy = notification.Body as IThingDataProxy<MyIdType>;
                        ViewComponent.RemoveUIElement(itemMediator.GetThingDataProxyView(itemProxy));
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.TILESIZEUPDATED_NOTIFICATION))
                    {
                        ViewComponent.TileSize = ModelFacade<MyIdType>.Instance.Game.TileSize;
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.MAXHEIGHTUPDATED_NOTIFICATION))
                    {
                        ViewComponent.MaxMapHeight = ModelFacade<MyIdType>.Instance.Game.MaxHeight;
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.MINHEIGHTUPDATED_NOTIFICATION))
                    {
                        ViewComponent.MinMapHeight = ModelFacade<MyIdType>.Instance.Game.MinHeight;
                    }
                    else if (notification.Name.Equals(ModelFacade<MyIdType>.Instance.Game.TILEHEIGHTUNITUPDATED_NOTIFICATION))
                    {
                        ViewComponent.TileHeightUnit = ModelFacade<MyIdType>.Instance.Game.TileHeightUnit;
                    }
                    break;
            }
            base.HandleNotification(notification);
        }

        /// <summary>
        /// Called by the View when the Mediator is registered
        /// </summary>
        override public void OnRegister()
        {
            
            ViewComponent.SetMapView(mapMediator.ViewComponent);
            //add dos items existentes?
            //itemMenuMediator.
            itemMediator.OnPositionChange += new Action<IThingDataProxy<MyIdType>>(itemMediator_OnPositionChange);
            ViewComponent.MyOnSizeChanged += new Action<Point>(ViewComponent_OnSizeChanged);
            //itemMediator.OnDirectionChange += new Action<IThingDataProxy<ItemVOId>>(itemMediator_OnDirectionChange);

            foreach (IThingDataProxy<MyIdType> itemProxy in proxy.Items.Values)
            {
                ViewComponent.AddUIElement(
                    itemMediator.GetThingDataProxyView(itemProxy),
                    itemProxy.Position,
                    proxy.Map.GetTileHeight(itemProxy.Position).Value);
            }
        }

        /// <summary>
        /// Called by the View when the Mediator is removed
        /// </summary>
        override public void OnRemove()
        {
            //Facade.RemoveMediator(mapMediator.MediatorName);
            //Facade.RemoveMediator(Menu.MediatorName);
           // Facade.RemoveMediator(MenuBar.MediatorName);
        }

        #endregion

        void UpdateItem(IThingDataProxy<MyIdType> item)
        {
            //TODO alturas intermedias
            ViewComponent.UpdateUIElement(
                    itemMediator.GetThingDataProxyView(item),
                    item.Position,
                    proxy.Map.GetTileHeight(item.MapPosition).Value);
        }

        void itemMediator_OnMapPositionChange(IThingDataProxy<MyIdType> item)
        {
            UpdateItem(item);
        }

        void itemMediator_OnHeightChange(IThingDataProxy<MyIdType> item)
        {
            UpdateItem(item);
        }

        void itemMediator_OnDirectionChange(IThingDataProxy<MyIdType> obj)
        {
            UpdateItem(obj);
        }

        protected virtual void ViewComponent_OnSizeChanged(Point size)
        {
            mapMediator.SetViewSize(size.X , size.Y);
        }
    }
}